using System.Text.Json.Serialization;
using Betalgo.Ranul.OpenAI.Contracts.Enums.Image;
using Betalgo.Ranul.OpenAI.Contracts.Interfaces;
using Betalgo.Ranul.OpenAI.Contracts.Responses.Base;

namespace Betalgo.Ranul.OpenAI.Contracts.Responses.Image;

/// <summary>
///     <see href="https://platform.openai.com/docs/api-reference/images/object">
///         OpenAI API documentation
///     </see>
///     The response from the image generation endpoint.
/// </summary>
public class ImageResponse : ResponseBase, IDefaultResult<string>, IDefaultResults<string>, IHasImageSize, IHasImageBackground, IHasImageOutputFormat, IHasImageQuality
{
    /// <summary>
    ///     Initializes a new instance of the <see cref="ImageResponse" /> class.
    /// </summary>
    public ImageResponse()
    {
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="ImageResponse" /> class.
    /// </summary>
    /// <param name="created">
    ///     The Unix timestamp (in seconds) of when the image was created.
    /// </param>
    public ImageResponse(int created)
    {
        Created = created;
    }


    /// <summary>
    ///     The Unix timestamp (in seconds) of when the image was created.
    /// </summary>
    [JsonPropertyName("created")]
    public int Created { get; set; }

    /// <summary>
    ///     The list of generated images.
    /// </summary>
    [JsonPropertyName("data")]
    public List<ImageDataResponse> Data { get; set; }

    /// <summary>
    ///     For <c>gpt-image-1</c> only, the token usage information for the image generation.
    /// </summary>
    [JsonPropertyName("usage")]
    public UsageResponse? Usage { get; set; }

    public string? Result => Data is { Count: > 0 } ? Data[0].Url ?? Data[0].B64Json ?? null : null;

    public List<string>? Results => Data is { Count: > 0 } ? Data.Select(x => x.Url ?? x.B64Json ?? string.Empty).Where(r => !string.IsNullOrEmpty(r)).ToList() : null;

    /// <summary>
    ///     The background parameter used for the image generation. Either <c>transparent</c> or <c>opaque</c>.
    /// </summary>
    [JsonPropertyName("background")]
    public ImageBackground? Background { get; set; }

    /// <summary>
    ///     The output format of the image generation. Either <c>png</c>, <c>webp</c>, or <c>jpeg</c>.
    /// </summary>
    [JsonPropertyName("output_format")]
    public ImageOutputFormat? OutputFormat { get; set; }

    /// <summary>
    ///     The quality of the image generated. Either <c>low</c>, <c>medium</c>, or <c>high</c>.
    /// </summary>
    [JsonPropertyName("quality")]
    public ImageQuality? Quality { get; set; }

    /// <summary>
    ///     The size of the image generated. Either <c>1024x1024</c>, <c>1024x1536</c>, or <c>1536x1024</c>.
    /// </summary>
    [JsonPropertyName("size")]
    public ImageSize? Size { get; set; }


    /// <summary>
    ///     Represents the content or the URL of an image generated by the OpenAI API.
    /// </summary>
    public class ImageDataResponse
    {
        /// <summary>
        ///     Initializes a new instance of the <see cref="ImageDataResponse" /> class.
        /// </summary>
        public ImageDataResponse()
        {
        }


        /// <summary>
        ///     The base64-encoded JSON of the generated image. Default value for <c>gpt-image-1</c>, and only present if
        ///     <c>response_format</c> is set to <c>b64_json</c> for <c>dall-e-2</c> and <c>dall-e-3</c>.
        /// </summary>
        [JsonPropertyName("b64_json")]
        public string? B64Json { get; set; }

        /// <summary>
        ///     When using <c>dall-e-2</c> or <c>dall-e-3</c>, the URL of the generated image if <c>response_format</c> is set to
        ///     <c>url</c> (default value). Unsupported for <c>gpt-image-1</c>.
        /// </summary>
        [JsonPropertyName("url")]
        public string? Url { get; set; }

        /// <summary>
        ///     For <c>dall-e-3</c> only, the revised prompt that was used to generate the image.
        /// </summary>
        [JsonPropertyName("revised_prompt")]
        public string? RevisedPrompt { get; set; }
    }
}